home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Tool Chest / Text / WASTE / WASTE 1.1.2 Distribution / WASTE Source / WEScraps.p < prev    next >
Encoding:
Text File  |  1995-10-12  |  13.3 KB  |  509 lines  |  [TEXT/CWIE]

  1. unit WEScraps;
  2.  
  3. { WASTE PROJECT: }
  4. { Routines for manipulating style scraps and object soups }
  5.  
  6. { Copyright © 1993-1994 Marco Piovanelli }
  7. { All Rights Reserved }
  8.  
  9. interface
  10.     uses
  11.         WEDrawing;
  12.  
  13.     function _WEPrependStyle (hStyleScrap: Handle;
  14.                                     var info: WERunInfo;
  15.                                     offsetDelta: LongInt): OSErr;
  16.     function _WEAppendStyle (hStyleScrap: Handle;
  17.                                     var info: WERunInfo;
  18.                                     offset: LongInt): OSErr;
  19.     function _WEPrependObject (hSoup: Handle;
  20.                                     var info: WERunInfo;
  21.                                     offsetDelta: LongInt): OSErr;
  22.     function _WEAppendObject (hSoup: Handle;
  23.                                     var info: WERunInfo;
  24.                                     offset: LongInt): OSErr;
  25.     function WECopyRange (rangeStart, rangeEnd: LongInt;
  26.                                     hText, hStyles, hSoup: Handle;
  27.                                     hWE: WEHandle): OSErr;
  28.     function WECopy (hWE: WEHandle): OSErr;
  29.  
  30. implementation
  31.     uses
  32.         Scrap, ToolUtils;
  33.  
  34.     function _WEPrependStyle (hStyleScrap: Handle;
  35.                                     var info: WERunInfo;
  36.                                     offsetDelta: LongInt): OSErr;
  37.  
  38. { compare the stylistic attributes in info with the first element of the specified }
  39. { style scrap: if they differ, prepend a new element to the style scrap. }
  40. { in any case, advance all character offsets in the style scrap by offsetDelta }
  41.  
  42.         label
  43.             1;
  44.         var
  45.             pScrap: TEStyleScrapPtr;
  46.             scrapSize: Size;
  47.             i: Integer;
  48.             err: OSErr;
  49.     begin
  50.         pScrap := TEStyleScrapHandle(hStyleScrap)^;
  51.         if (_WEBlockCmp(@pScrap^.scrpStyleTab[0].scrpTEAttrs, @info.runAttrs.runTEAttrs, SizeOf(info.runAttrs.runTEAttrs)) = false) then
  52.             begin
  53.  
  54. { lengthen the style scrap }
  55.                 scrapSize := GetHandleSize(hStyleScrap);
  56.                 SetHandleSize(hStyleScrap, scrapSize + SizeOf(TEStyleScrapElement));
  57.                 err := MemError;
  58.                 if (err <> noErr) then
  59.                     goto 1;
  60.  
  61. { move old contents forward }
  62.                 pScrap := TEStyleScrapHandle(hStyleScrap)^;
  63.                 BlockMoveData(@pScrap^.scrpStyleTab[0], @pScrap^.scrpStyleTab[1], scrapSize - SizeOf(pScrap^.scrpNStyles));
  64.  
  65. { insert a new element at the beginning }
  66.                 pScrap^.scrpStyleTab[0].scrpStartChar := 0;
  67.                 pScrap^.scrpStyleTab[0].scrpTEAttrs := info.runAttrs.runTEAttrs;
  68.  
  69. { increment scrap counter }
  70.                 pScrap^.scrpNStyles := pScrap^.scrpNStyles + 1;
  71.  
  72.             end;  { if not _WEBlockCmp }
  73.  
  74. { update char offsets within the style scrap }
  75.         for i := pScrap^.scrpNStyles - 1 downto 1 do
  76.             with pScrap^.scrpStyleTab[i] do
  77.                 scrpStartChar := scrpStartChar + offsetDelta;
  78.  
  79. { clear result code }
  80.         err := noErr;
  81.  
  82. 1:
  83. { return result code }
  84.         _WEPrependStyle := err;
  85.  
  86.     end;  { _WEPrependStyle }
  87.  
  88.     function _WEAppendStyle (hStyleScrap: Handle;
  89.                                     var info: WERunInfo;
  90.                                     offset: LongInt): OSErr;
  91.  
  92. { compare the stylistic attributes in info with the last element of the specified }
  93. { style scrap: if they differ, append a new element to the style scrap. }
  94.  
  95.         label
  96.             1;
  97.         var
  98.             pScrap: TEStyleScrapPtr;
  99.             element: TEStyleScrapElement;
  100.             err: OSErr;
  101.     begin
  102.         pScrap := TEStyleScrapHandle(hStyleScrap)^;
  103.         if (_WEBlockCmp(@pScrap^.scrpStyleTab[pScrap^.scrpNStyles - 1].scrpTEAttrs, @info.runAttrs.runTEAttrs, SizeOf(info.runAttrs.runTEAttrs)) = false) then
  104.             begin
  105.  
  106. { create a new style scrap element }
  107.                 element.scrpStartChar := offset;
  108.                 element.scrpTEAttrs := info.runAttrs.runTEAttrs;
  109.  
  110. { append it at the end of the style scrap }
  111.                 err := PtrAndHand(@element, hStyleScrap, SizeOf(element));
  112.                 if (err <> noErr) then
  113.                     goto 1;
  114.  
  115. { increment scrap counter }
  116.                 pScrap := TEStyleScrapHandle(hStyleScrap)^;
  117.                 pScrap^.scrpNStyles := pScrap^.scrpNStyles + 1;
  118.  
  119.             end;  { if not _WEBlockCmp }
  120.  
  121. { clear result code }
  122.         err := noErr;
  123.  
  124. 1:
  125. { return result code }
  126.         _WEAppendStyle := err;
  127.  
  128.     end;  { _WEAppendStyle }
  129.  
  130.     function _WEPrependObject (hSoup: Handle;
  131.                                     var info: WERunInfo;
  132.                                     offsetDelta: LongInt): OSErr;
  133.  
  134. { if info describes an embedded object, prepend a new object descriptor, }
  135. { complete with the associated object data, to the specified soup. }
  136. { in any case, advance all character offsets in the soup by offsetDelta }
  137.  
  138.         label
  139.             1;
  140.         var
  141.             pDesc: WEObjectDescPtr;
  142.             pSoup: WESoupPtr;
  143.             soupSize, objectDataSize, extraSize: Size;
  144.             err: OSErr;
  145.     begin
  146.  
  147. { get size of existing soup }
  148.         soupSize := GetHandleSize(hSoup);
  149.  
  150. { extract object descriptor handle from WERunInfo record }
  151. { if hObject is non-NIL, info describes an embedded object }
  152.         if (info.runAttrs.runStyle.tsObject <> kNullObject) then
  153.             begin
  154.                 pDesc := WEObjectDescHandle(info.runAttrs.runStyle.tsObject)^;
  155.  
  156. { get size of object data }
  157.                 objectDataSize := GetHandleSize(pDesc^.objectDataHandle);
  158.  
  159. { extra size to add to existing soup is descriptor size + object data size }
  160.                 extraSize := SizeOf(WESoup) + objectDataSize;
  161.  
  162. { resize the soup }
  163.                 SetHandleSize(hSoup, soupSize + extraSize);
  164.                 err := MemError;
  165.                 if (err <> noErr) then
  166.                     goto 1;
  167.  
  168. { move old contents forward }
  169.                 pSoup := WESoupHandle(hSoup)^;
  170.                 BlockMoveData(Ptr(pSoup), Ptr(LongInt(pSoup) + extraSize), soupSize);
  171.  
  172. { insert the new object descriptor at the beginning }
  173.                 _WEBlockClr(Ptr(pSoup), SizeOf(WESoup));
  174.                 pDesc := WEObjectDescHandle(info.runAttrs.runStyle.tsObject)^;
  175.                 pSoup^.soupType := pDesc^.objectType;
  176.                 pSoup^.soupSize := pDesc^.objectSize;
  177.                 pSoup^.soupDataSize := objectDataSize;
  178.  
  179. { then copy the object data }
  180.                 BlockMoveData(pDesc^.objectDataHandle^, Ptr(LongInt(pSoup) + SizeOf(WESoup)), objectDataSize);
  181.  
  182.             end
  183.         else
  184.             begin
  185.                 pSoup := WESoupHandle(hSoup)^;
  186.                 extraSize := 0;
  187.             end;
  188.  
  189. { update char offsets within the soup }
  190.         while (soupSize > 0) do
  191.             begin
  192.                 pSoup := WESoupPtr(LongInt(pSoup) + extraSize);
  193.                 pSoup^.soupOffset := pSoup^.soupOffset + offsetDelta;
  194.                 extraSize := pSoup^.soupDataSize + SizeOf(WESoup);
  195.                 soupSize := soupSize - extraSize;
  196.             end;
  197.  
  198. { clear result code }
  199.         err := noErr;
  200.  
  201. 1:
  202. { return result code }
  203.         _WEPrependObject := err;
  204.  
  205.     end;  { _WEPrependObject }
  206.  
  207.     function _WEAppendObject (hSoup: Handle;
  208.                                     var info: WERunInfo;
  209.                                     offset: LongInt): OSErr;
  210.  
  211. { if info describes an embedded object, append a new object descriptor, }
  212. { complete with the associated object data, to the specified soup. }
  213.  
  214.         label
  215.             1;
  216.         var
  217.             pDesc: WEObjectDescPtr;
  218.             hObjectData: Handle;
  219.             soupItem: WESoup;
  220.             saveDataLock: Boolean;
  221.             err: OSErr;
  222.     begin
  223.         if (info.runAttrs.runStyle.tsObject <> kNullObject) then
  224.             begin
  225.                 pDesc := WEObjectDescHandle(info.runAttrs.runStyle.tsObject)^;
  226.                 hObjectData := pDesc^.objectDataHandle;
  227.  
  228. { fill in a soup item }
  229.                 _WEBlockClr(@soupItem, SizeOf(soupItem));
  230.                 soupItem.soupOffset := offset;
  231.                 soupItem.soupType := pDesc^.objectType;
  232.                 soupItem.soupSize := pDesc^.objectSize;
  233.                 soupItem.soupDataSize := GetHandleSize(hObjectData);
  234.  
  235. { append it to the soup handle }
  236.                 err := PtrAndHand(@soupItem, hSoup, SizeOf(soupItem));
  237.                 if (err <> noErr) then
  238.                     goto 1;
  239.  
  240. { append the actual object data to the soup handle }
  241.                 saveDataLock := _WESetHandleLock(hObjectData, true);
  242.                 err := PtrAndHand(hObjectData^, hSoup, soupItem.soupDataSize);
  243.                 if (_WESetHandleLock(hObjectData, saveDataLock)) then
  244.                     ;
  245.                 if (err <> noErr) then
  246.                     goto 1;
  247.  
  248.             end;  { if object reference is not NIL }
  249.  
  250. { clear result code }
  251.         err := noErr;
  252.  
  253. 1:
  254. { return result code }
  255.         _WEAppendObject := err;
  256.  
  257.     end;  { _WEAppendObject }
  258.  
  259.     function WECopyRange (rangeStart, rangeEnd: LongInt;
  260.                                     hText, hStyles, hSoup: Handle;
  261.                                     hWE: WEHandle): OSErr;
  262.  
  263. { Make a copy of the specified range of text: store the characters in hText }
  264. { and the associated style scrap in hStyles.  The handles are resized as necessary. }
  265. { Specify NIL in hText or hStyles if you don't want the corresponding info returned. }
  266.  
  267.         label
  268.             1;
  269.         var
  270.             pWE: WEPtr;
  271.             rangeLength: LongInt;
  272.             firstRun, nRuns, i: LongInt;
  273.             startChar: LongInt;
  274.             info: WERunInfo;
  275.             pElement: Ptr;
  276. {$IFC NOT UNDEFINED THINK_PASCAL}
  277.             longMulResult: Int64Bit;
  278. {$ENDC}
  279.             saveWELock: Boolean;
  280.             err: OSErr;
  281.     begin
  282.  
  283. { lock the WE record }
  284.         saveWELock := _WESetHandleLock(hWE, true);
  285.         pWE := hWE^;
  286.  
  287. { range-check parameters and reorder them if necessary }
  288.         rangeStart := _WEPinInRange(rangeStart, 0, pWE^.textLength);
  289.         rangeEnd := _WEPinInRange(rangeEnd, 0, pWE^.textLength);
  290.         _WEReorder(rangeStart, rangeEnd);
  291.         rangeLength := rangeEnd - rangeStart;
  292.  
  293.         if (hText <> nil) then
  294.             begin
  295.  
  296. { resize the given handle }
  297.                 SetHandleSize(hText, rangeLength);
  298.                 err := MemError;
  299.                 if (err <> noErr) then
  300.                     goto 1;
  301.  
  302. { copy the text range }
  303.                 BlockMoveData(Ptr(LongInt(pWE^.hText^) + rangeStart), hText^, rangeLength);
  304.  
  305.             end;  { if (hText <> NIL) }
  306.  
  307. { make the soup handle zero-length }
  308.         if (hSoup <> nil) then
  309.             begin
  310.                 SetHandleSize(hSoup, 0);
  311.                 err := MemError;
  312.                 if (err <> noErr) then
  313.                     goto 1;
  314.             end;
  315.  
  316.         if (hStyles <> nil) or (hSoup <> nil) then
  317.             begin
  318.  
  319. { count how many style runs there are in the selection range }
  320.                 firstRun := _WEOffsetToRun(rangeStart, hWE);
  321.                 nRuns := _WEOffsetToRun(rangeEnd - 1, hWE) - firstRun + 1;
  322.  
  323.                 if (hStyles <> nil) then
  324.                     begin
  325.  
  326. { resize the given style scrap handle and lock it in high heap }
  327.  
  328. { (NOTE: we need to multiply two 32-bit ints: if we're generating 68000 code, }
  329. {     this will compile into a call to the compiler runtime library: a possible way }
  330. {     to avoid this is to use the Toolbox LongMul routine.) }
  331.  
  332. {$IFC NOT UNDEFINED THINK_PASCAL}
  333.                         LongMul(nRuns, SizeOf(ScrpSTElement), longMulResult);
  334.                         SetHandleSize(hStyles, longMulResult.loLong + 2);
  335. {$ELSEC}
  336.                         SetHandleSize(hStyles, (nRuns * SizeOf(ScrpSTElement)) + 2);
  337. {$ENDC}
  338.  
  339.                         err := MemError;
  340.                         if (err <> noErr) then
  341.                             goto 1;
  342.                         HLockHi(hStyles);
  343.                         pElement := hStyles^;
  344.  
  345. { fill in the style count in the style scrap }
  346. { *** POTENTIAL PROBLEM: if nRuns > 32767, scrpNStyles will be invalid *** }
  347.                         IntegerPtr(pElement)^ := nRuns;
  348.                         pElement := Ptr(LongInt(pElement) + SizeOf(Integer));
  349.  
  350.                     end;  { if hStyles <> NIL }
  351.  
  352. { loop through every style run in the selection range }
  353.                 for i := 0 to nRuns - 1 do
  354.                     begin
  355.                         _WEGetIndStyle(firstRun + i, info, hWE);
  356.  
  357. { calculate the start character for this style run, relative to the beginning of the range }
  358.                         startChar := info.runStart - rangeStart;
  359.                         if (startChar < 0) then
  360.                             begin
  361.                                 startChar := 0;
  362.                                 info.runAttrs.runStyle.tsObject := kNullObject;
  363.                             end;
  364.  
  365. { fill in an item in the style scrap }
  366.                         if (hStyles <> nil) then
  367.                             begin
  368.                                 info.runAttrs.runStyle.tsFlags := 0;        { don't export internal flags }
  369.                                 TEStyleScrapElementPtr(pElement)^.scrpStartChar := startChar;
  370.                                 TEStyleScrapElementPtr(pElement)^.scrpTEAttrs := info.runAttrs.runTEAttrs;
  371.                                 pElement := Ptr(LongInt(pElement) + SizeOf(TEStyleScrapElement));
  372.                             end;
  373.  
  374.                         if (hSoup <> nil) then
  375.                             begin
  376.  
  377. { if this style run references an embedded object, append it to the "soup" }
  378.                                 err := _WEAppendObject(hSoup, info, startChar);
  379.                                 if (err <> noErr) then
  380.                                     goto 1;
  381.                             end;
  382.  
  383.                     end;  { for }
  384.             end;
  385.  
  386. { clear result code }
  387.         err := noErr;
  388.  
  389. 1:
  390. { return result code }
  391.         WECopyRange := err;
  392.  
  393. { unlock the style scrap handle }
  394.         if (hStyles <> nil) then
  395.             HUnlock(hStyles);
  396.  
  397. { unlock the WE record }
  398.         if (_WESetHandleLock(hWE, saveWELock)) then
  399.             ;
  400.  
  401.     end;  { WECopyRange }
  402.  
  403.     function WECopy (hWE: WEHandle): OSErr;
  404.  
  405. { Copy the selection range to the desk scrap }
  406.  
  407.         label
  408.             1;
  409.         type
  410.             AEDescPtr = ^AEDesc;
  411.             AEDescHandle = ^AEDescPtr;
  412.         var
  413.             pWE: WEPtr;
  414.             d: array[0..2] of AEDesc;
  415.             hObjectDesc: WEObjectDescHandle;
  416.             i, numTypes: Integer;
  417.             hItem: Handle;
  418.             itemSize: Size;
  419.             disposeData: Boolean;
  420.             saveDataLock, saveWELock: Boolean;
  421.             err: OSErr;
  422.     begin
  423.         d[0].dataHandle := nil;
  424.         d[1].dataHandle := nil;
  425.         d[2].dataHandle := nil;
  426.         disposeData := false;
  427.  
  428. { lock the WE record }
  429.         saveWELock := _WESetHandleLock(hWE, true);
  430.         pWE := hWE^;
  431.  
  432. { return weEmptySelectionErr if the selection range is empty }
  433.         err := weEmptySelectionErr;
  434.         if (pWE^.selStart = pWE^.selEnd) then
  435.             goto 1;
  436.  
  437. { clear the desk scrap }
  438.         err := ZeroScrap;
  439.         if (err <> noErr) then
  440.             goto 1;
  441.  
  442. { if the selection range consists of an embedded object, copy that }
  443.         if (WEGetSelectedObject(hObjectDesc, hWE) = noErr) then
  444.             begin
  445.                 d[0] := AEDescHandle(hObjectDesc)^^;
  446.                 numTypes := 1;
  447.             end
  448.         else
  449.             begin
  450.  
  451. { allocate three zero-length handles to hold the text, the styles and the "soup" }
  452.                 for i := 0 to 2 do
  453.                     begin
  454.                         err := _WEAllocate(0, kAllocTemp, d[i].dataHandle);
  455.                         if (err <> noErr) then
  456.                             goto 1;
  457.                     end;  { for }
  458.  
  459. { make a copy of the selection text, styles and soup }
  460.                 err := WECopyRange(pWE^.selStart, pWE^.selEnd, d[0].dataHandle, d[1].dataHandle, d[2].dataHandle, hWE);
  461.                 if (err <> noErr) then
  462.                     goto 1;
  463.  
  464. { tag the data }
  465.                 d[0].descriptorType := kTypeText;
  466.                 d[1].descriptorType := kTypeStyles;
  467.                 d[2].descriptorType := kTypeSoup;
  468.                 numTypes := 3;
  469.                 disposeData := true;
  470.             end;
  471.  
  472. { copy the items to the desk scrap }
  473.         for i := 0 to numTypes - 1 do
  474.             begin
  475.                 hItem := d[i].dataHandle;
  476.                 itemSize := GetHandleSize(hItem);
  477.                 if (itemSize > 0) then
  478.                     begin
  479.                         saveDataLock := _WESetHandleLock(hItem, true);
  480.                         err := PutScrap(itemSize, d[i].descriptorType, hItem^);
  481.                         if (_WESetHandleLock(hItem, saveDataLock)) then
  482.                             ;
  483.                         if (err <> noErr) then
  484.                             goto 1;
  485.                     end;
  486.             end;  { for }
  487.  
  488. { clear result code }
  489.         err := noErr;
  490.  
  491. 1:
  492. { return result code }
  493.         WECopy := err;
  494.  
  495. { clean up }
  496.         if (disposeData) then
  497.             begin
  498.                 _WEForgetHandle(d[0].dataHandle);
  499.                 _WEForgetHandle(d[1].dataHandle);
  500.                 _WEForgetHandle(d[2].dataHandle);
  501.             end;
  502.  
  503. { unlock the WE record }
  504.         if (_WESetHandleLock(hWE, saveWELock)) then
  505.             ;
  506.  
  507.     end;  { WECopy }
  508.  
  509. end.